(*****************************************************************************
 * Delphi Plug-in Framework (DPF)
 * Copyright (C) 2006-2007 Tao Yuan
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the
 * License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.                                                               }
 *
 * The Initial Developer of the Original Code is Tao Yuan. Portions created by
 * Tao Yuan are Copyright (C) Tao Yuan (taoy.cn att gmail dott com)
 * All rights reserved.
 *****************************************************************************)
unit RDObjectFactory;

interface

uses
  Classes,
  Rcl,
  RdClasses, RDPluginRegistry, RDPluginManager, RDPathResolver;

type
  TObjectFactoryClass = class of TObjectFactory;
  TObjectFactory = class(TRdLogPersistent)
  private
    class function findProperty(aClass: TClass; props: TExtendedProperties): string;
    class function loadClass(aClassName: string): TClass;
    class function loadProperties(aClass: TClass): TExtendedProperties;
  protected
    procedure configure(configuration: TExtendedProperties); virtual; abstract;
  public
    constructor Create; override;
    destructor Destroy; override;
    function createManager: TPluginManager; overload;
    function createManager(registry: IPluginRegistry; pathResolver: IPathResolver):
        TPluginManager; overload; virtual; abstract;
    function createPathResolver: IPathResolver; virtual; abstract;
    function createRegistry: IPluginRegistry; virtual; abstract;
    class function newFactory: TObjectFactory; overload;
    class function newFactory(config: TExtendedProperties): TObjectFactory;
        overload;
  end;

implementation

uses
  SysUtils,
  DPFLog,
  RDStandardObjectFactory;

constructor TObjectFactory.Create;
begin
  inherited Create;
//  Owner := True;
end;

destructor TObjectFactory.Destroy;
begin
  inherited;
  // TODO -cMM: TObjectFactory.Destroy default body inserted
end;

function TObjectFactory.createManager: TPluginManager;
begin
  Result := createManager(createRegistry, createPathResolver);;
end;

class function TObjectFactory.findProperty(aClass: TClass; props:
    TExtendedProperties): string;
var
  log: ILog;
  name: string;
begin
  log := DPFLog.LogFactory.getLogger(TObjectFactory);
  name := aClass.ClassName;
  if props <> nil then
  begin
    Result := props.GetProperty(name);
    if Result <> '' then
    begin
      log.debug('property ' + name //$NON-NLS-1$
          + ' found in properties file');
      Exit;
    end;
  end;
  log.debug('no property ' + name //$NON-NLS-1$
          + ' found'); //$NON-NLS-1$
end;

class function TObjectFactory.loadClass(aClassName: string): TClass;
begin
  Result := GetClass(aClassName);
end;

class function TObjectFactory.loadProperties(aClass: TClass):
    TExtendedProperties;
var
  log: ILog;
  name: string;
  url: string;
  strm: TStream;
begin
  log := DPFLog.LogFactory.getLogger(TObjectFactory);
  url := 'dpf.properties';
  if FileExists(url) then
  begin
    try
      strm := TFileStream.Create(url, fmOpenRead);
      try
        Result := TExtendedProperties.Create;
        Result.Load(strm);
        log.debug('loaded dpf.properties from ' + url);
      finally
        strm.Free;
      end;
    except
      log.error('failed loading dpf.properties');
    end;
  end;

end;

class function TObjectFactory.newFactory: TObjectFactory;
begin
  Result := newFactory(nil);
end;

class function TObjectFactory.newFactory(config: TExtendedProperties):
    TObjectFactory;
var
  log: ILog;
  props: TExtendedProperties;
  className: string;
begin
  log := DPFLog.LogFactory.getLogger(TObjectFactory);

  if (config <> nil) then
      props := config
  else
      props := loadProperties(TObjectFactory);

  className := findProperty(TObjectFactory, props);
  try
      if (className = '') then
          result := TStandardObjectFactory.Create
      else 
          result := TObjectFactoryClass(loadClass(className)).newFactory;
  except

  end;
//  } catch (ClassNotFoundException cnfe) {
//      log.fatal("failed instantiating object factory " //$NON-NLS-1$
//              + className, cnfe);
//      throw new Error("failed instantiating object factory " //$NON-NLS-1$
//              + className, cnfe);
//  } catch (IllegalAccessException iae) {
//      log.fatal("failed instantiating object factory " //$NON-NLS-1$
//              + className, iae);
//      throw new Error("failed instantiating object factory " //$NON-NLS-1$
//              + className, iae);
//  } catch (SecurityException se) {
//      log.fatal("failed instantiating object factory " //$NON-NLS-1$
//              + className, se);
//      throw new Error("failed instantiating object factory " //$NON-NLS-1$
//              + className, se);
//  } catch (InstantiationException ie) {
//      log.fatal("failed instantiating object factory " //$NON-NLS-1$
//              + className, ie);
//      throw new Error("failed instantiating object factory " //$NON-NLS-1$
//              + className, ie);
//  }
  result.configure(props);
  log.debug('object factory instance created - ' + result.ClassName); //$NON-NLS-1$
end;

end.
